package eiisan.java8mergelist;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

import java.sql.SQLOutput;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;

/**
 * Java8MergeListTest
 * @author gragonfly
 * @date 2019/7/9
 **/
public class Java8MergeListTest {

    @Test
    public void mergeMapValuesTest(){
        Map<Integer, ListContainer> map = Maps.newHashMap();
        List<AClass> aClassList1 = Lists.newArrayList();
        AClass aClass = new AClass(1, "name11", "xx1");
        aClassList1.add(aClass);
        aClassList1.add(new AClass(2, "name22", "xx2"));
        aClassList1.add(new AClass(3, "name33", "xx3"));

        List<AClass> aClassList2 = Lists.newArrayList();
        aClassList2.add(aClass);
        aClassList2.add(new AClass(5, "name44", "xx4"));
        aClassList2.add(new AClass(6, "name55", "xx5"));

        /*交集*/
        /*[AClass(id=1, name=name11, nickname=xx1)]*/
        List<AClass> intersectResult = aClassList1.stream().filter(aClassList2::contains).collect(Collectors.toList());
        System.out.println(intersectResult);

        /*并集*/
        List<AClass> unionResult = Stream.of(aClassList1, aClassList2).flatMap(Collection::stream).distinct().collect(Collectors.toList());
        assertEquals(unionResult.size(), 5);
        System.out.println(unionResult);

        /*差集*/
        /*[AClass(id=2, name=name22, nickname=xx2), AClass(id=3, name=name33, nickname=xx3)]*/
        List<AClass> differenceResult = aClassList1.stream().filter(x -> !aClassList2.contains(x)).collect(Collectors.toList());
        System.out.println(differenceResult);

        map.put(1, new ListContainer(aClassList1));
        map.put(2, new ListContainer(aClassList2));

        /*合并多个list*/
        List<AClass> aClassListResult = map.values().stream().flatMap(listContainer -> listContainer.getLst().stream()).collect(Collectors.toList());
        /*注意跟并集的区别*/
        assertEquals(aClassListResult.size(), 6);
        System.out.println(aClassListResult);
    }

    @Test
    public void intersectByKeyTest(){
        //相交

        List<Data2> listOfData2 = new ArrayList<Data2>();

        listOfData2.add(new Data2(10501, "JOE"  , "Type1"));
        listOfData2.add(new Data2(10603, "SAL"  , "Type5"));
        listOfData2.add(new Data2(40514, "PETER", "Type4"));
        listOfData2.add(new Data2(59562, "JIM"  , "Type2"));
        listOfData2.add(new Data2(29415, "BOB"  , "Type1"));
        listOfData2.add(new Data2(61812, "JOE"  , "Type9"));
        listOfData2.add(new Data2(98432, "JOE"  , "Type7"));
        listOfData2.add(new Data2(62556, "JEFF" , "Type1"));
        listOfData2.add(new Data2(10599, "TOM"  , "Type4"));


        List<Data1> listOfData1 = new ArrayList<Data1>();

        listOfData1.add(new Data1(10501, "JOE"    ,3000000));
        listOfData1.add(new Data1(10501, "JOE222"    ,3000022));
        listOfData1.add(new Data1(10603, "SAL"    ,6225000));
        listOfData1.add(new Data1(40514, "PETER"  ,2005000));
        listOfData1.add(new Data1(59562, "JIM"    ,3000000));
        listOfData1.add(new Data1(29415, "BOB"    ,3000000));
        /*List<OutputData> result2 = listOfData1.stream()
                    .flatMap(
                            x -> {
                                System.out.println(x.name);
                                return listOfData2.stream()
                                        .filter(y -> x.getId() == y.getId())
                                        .map(y -> {
                                            System.out.println("---" + y.name);
                                            return new OutputData(y.getId(), x.getName(), y.getType(), x.getAmount());
                                        });
                            })
                    .collect(Collectors.toList());*/
        List<OutputData> result = listOfData1.stream()
                .flatMap(x -> listOfData2.stream()
                        .filter(y -> x.getId() == y.getId())
                        .map(y -> new OutputData(y.getId(), x.getName(), y.getType(), x.getAmount())))
                .collect(Collectors.toList());

        System.out.println(result);

        /*difference by key*/
        List<Data1> data1IntersectResult = listOfData1.stream().filter(data1 -> listOfData2.stream().map(Data2::getId).collect(Collectors.toList()).contains(data1.getId())).collect(Collectors.toList());
        System.out.println(data1IntersectResult);
        data1IntersectResult.forEach(System.out::println);
    }

    @Test
    public void flatMapToIntTest() {
        List<List<String>> listOfLists = Arrays.asList(
                Arrays.asList("1", "2"),
                Arrays.asList("5", "6"),
                Arrays.asList("3", "4")
        );

        IntStream intStream =
                listOfLists.stream()
                        .flatMapToInt(childList ->
                                childList.stream()
                                        .mapToInt(Integer::new));

        int sum = intStream.peek(System.out::println).sum();
        System.out.println("sum: " + sum);
    }


    @Data
    @AllArgsConstructor
    public class ListContainer {
        private List<AClass> lst;
    }

    @Data
    @AllArgsConstructor
    public class AClass {
        private int id;
        private String name;
        private String nickname;
    }

    @Data
    @AllArgsConstructor
    public class Data1 {
        private int id;
        private String name;
        private int amount;
    }

    @Data
    @AllArgsConstructor
    public class Data2 {
        private int id;
        private String name;
        private String type;
    }

    @Data
    @AllArgsConstructor
    public class OutputData {
        private int id;
        private String name;
        private String type;
        private int amount;
    }


}
